package com.liuzhiqiang.oauth.confing.oauth;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.liuzhiqiang.oauth.vo.AjaxResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author 刘志强
 * @title: ResourceServerConfig
 * @projectName housekeeper-data-center-back
 * @description: TODO
 * @date 2021/7/2920:05
 */
@Configuration
// 启用资源服务
@EnableResourceServer
// 开启注解形式控制
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private TokenStore tokenStore;


    /**
     * 配置接口访问策略信息
     *
     * @param httpSecurity
     * @throws Exception
     */
    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                // 配置接口访问策略信息
                .authorizeRequests()
                // /test3 可以匿名访问
                .antMatchers("/test3").permitAll()
                //任何请求都需要身份认证
                .anyRequest().authenticated()
                // 配置异常处理器
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(this::commence)

                .and()
                .csrf()
                .disable();    //禁用CSRF
    }

    /**
     * 配置资源服务安全
     * 用户及权限等信息从 tokenStore 读取，及异常处理
     *
     * @param resourceServerSecurityConfigurer
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer resourceServerSecurityConfigurer) {
        resourceServerSecurityConfigurer.tokenStore(tokenStore);
        resourceServerSecurityConfigurer.authenticationEntryPoint(this::commence);
    }

    /**
     * 异常处理
     *
     * @param request
     * @param response
     * @param authException
     * @throws IOException
     */
    public void commence(HttpServletRequest request, HttpServletResponse response,
                         AuthenticationException authException) throws IOException {
        log.error(authException.getMessage());
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out;

        AjaxResult ajaxResult = null;
        if (authException instanceof InsufficientAuthenticationException) {
            ajaxResult = AjaxResult.error(HttpStatus.UNAUTHORIZED.value(), "身份验证异常，令牌已过期或未携带令牌");
        } else {
            ajaxResult = AjaxResult.error(HttpStatus.UNAUTHORIZED.value(), authException.getMessage());
        }
        out = response.getWriter();
        out.write(new ObjectMapper().writeValueAsString(ajaxResult));
        out.flush();
        out.close();
    }
}
